﻿using System.Collections;
using System.Text.Json.Serialization;

namespace LightCAD.Core
{
    public abstract partial class Element : LcadObject
    {
        [JsonIgnore]
        public ElementType Type { get; protected set; }//方便进行switch/case遍历

        [JsonInclude]
        public ElementStyle Style { get; internal set; }
        public bool Disabled { get; set; }
        public bool Hidden { get; set; }

        protected Box2d? _boudingBox;

        [JsonIgnore]
        public bool IsDragging { get; set; }
        [JsonIgnore]
        public bool IsSelected { get; set; }
        [JsonIgnore]
        public bool IsHovered { get; set; }

        public Dictionary<string, object> UserData { get; set; }
       
        internal void SetStyle(ElementStyle style, bool fireChangedEvent = true)
        {
            if (this.Style == style) return;

            if (fireChangedEvent) PropertyChangedBefore(nameof(Style), this.Style, style);
            var oldValue = this.Style;
            this.Style = style;
            if (fireChangedEvent) PropertyChangedAfter(nameof(Style), oldValue, this.Style);
        }

        public void SetDisabled(bool disabled, bool fireChangedEvent = true)
        {
            if (this.Disabled == disabled) return;
            if (fireChangedEvent) PropertyChangedBefore(nameof(Disabled), this.Disabled, disabled);
            var oldValue = this.Disabled;
            this.Disabled = disabled;
            if (fireChangedEvent) PropertyChangedAfter(nameof(Disabled), oldValue, this.Disabled);
        }
        public void SetHidden(bool hidden, bool fireChangedEvent = true)
        {
            if (this.Hidden == hidden) return;
            if (fireChangedEvent) PropertyChangedBefore(nameof(Hidden), this.Hidden, hidden);
            var oldValue = this.Hidden;
            this.Hidden = hidden;
            if (fireChangedEvent) PropertyChangedAfter(nameof(Hidden), oldValue, this.Hidden);
        }
        public virtual void Translate(double dx, double dy)
        {
        }
        public virtual void Copy(Element src)
        {
            base.Copy(src);
            this.Disabled = src.Disabled;
            this.Hidden = src.Hidden;
            this.Style = src.Style;
        }
        [JsonIgnore]
        public Box2d BoundingBox
        {
            get
            {
                if (this._boudingBox == null)
                {
                    this._boudingBox = GetBoundingBox();
                }
                return this._boudingBox.Value;
            }
        }
        public virtual Box2d GetBoundingBox()
        {
            return new Box2d();
        }
        public Box2d UpdateBoundingBox()
        {
            this._boudingBox = null;
            return this.BoundingBox;
        }
        public void ResetBoundingBox()
        {
            this._boudingBox = null;
        }
        protected override void OnPropertyChange(string propertyName, PropertyGroup extPropGroup, Property extProp)
        {
            ResetBoundingBox();
        }
        public virtual bool IntersectWithBox(Box2d testBox)
        {
            return false;
        }
        public virtual bool IncludeByBox(Box2d testBox)
        {
            return false;
        }
        public abstract Element Clone();


    }


    public class ElementCollection : IList<Element>
    {
        private Dictionary<int, Element> _dict = new Dictionary<int, Element>();
        private List<Element> _list = new List<Element>();

        public ElementCollection()
        {
        }
        [JsonIgnore]
        public int Count => _list.Count;

        public bool IsReadOnly => false;

        public Element this[int index]
        {
            get => _list[index];

            set
            {
                _list[index] = value;
                _dict.Add(value.Id, value);
            }
        }

        public int IndexOf(Element item)
        {
            return _list.IndexOf(item);
        }

        public void Insert(int index, Element item)
        {
            _list.Insert(index, item);
            _dict.Add(item.Id, item);
        }

        public void RemoveAt(int index)
        {
            _dict.Remove(_list[index].Id);
            _list.RemoveAt(index);
        }

        public void Add(Element item)
        {
            _list.Add(item);
            _dict.Add(item.Id, item);
        }

        public void Clear()
        {
            _list.Clear();
            _dict.Clear();
        }

        public bool Contains(Element item)
        {
            return _dict.ContainsKey(item.Id);
        }

        public void CopyTo(Element[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        public bool Remove(Element item)
        {
            if (!_dict.ContainsKey(item.Id))
                return false;
            else
            {
                _dict.Remove(item.Id);
                _list.Remove(item);
                return true;
            }
        }

        public IEnumerator<Element> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _list.GetEnumerator();
        }
    }

    public class ReadonlyElementCollection : IList<Element>
    {
        private Dictionary<int, Element> _dict = new Dictionary<int, Element>();
        private List<Element> _list = new List<Element>();

        public int Count => _list.Count;

        public bool IsReadOnly => true;

        public Element this[int index]
        {
            get => _list[index];
            set => _list[index] = value;
        }

        public int IndexOf(Element item)
        {
            return _list.IndexOf(item);
        }
        internal void AddItem(Element item)
        {
            _list.Add(item);
            _dict.Add(item.Id, item);
        }
        void IList<Element>.Insert(int index, Element item)
        {
            _list.Insert(index, item);
            _dict.Add(item.Id, item);
        }

        void IList<Element>.RemoveAt(int index)
        {
            _dict.Remove(_list[index].Id);
            _list.RemoveAt(index);
        }

        void ICollection<Element>.Add(Element item)
        {
            _list.Add(item);
            _dict.Add(item.Id, item);
        }

        void ICollection<Element>.Clear()
        {
            _list.Clear();
            _dict.Clear();
        }

        public bool Contains(Element item)
        {
            return _dict.ContainsKey(item.Id);
        }

        public void CopyTo(Element[] array, int arrayIndex)
        {
            _list.CopyTo(array, arrayIndex);
        }

        bool ICollection<Element>.Remove(Element item)
        {
            if (!_dict.ContainsKey(item.Id))
                return false;
            else
            {
                _dict.Remove(item.Id);
                _list.Remove(item);
                return true;
            }
        }

        public IEnumerator<Element> GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _list.GetEnumerator();
        }

        public ElementCollection CloneEditable()
        {
            var elements = new ElementCollection();
            foreach (var item in _list)
            {
                elements.Add(item);
            }
            return elements;
        }

    }
}